

const { ccclass, property, executeInEditMode, menu } = cc._decorator;
const gfx = cc['gfx'];


const vertexFmt2D = new gfx.VertexFormat([
    { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
    { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
    // { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_FLOAT32, num: 3 },
])

@ccclass
// @executeInEditMode
@menu('cccframework/Mesh2D')
export default class Mesh2D extends cc.Component {

    get vertexesCount() {
        return 4;
    }
    get indicesCount() {
        return (this.vertexesCount - 2) * 3;
    }
    ctx: cc.Graphics = null;
    @property(cc.MeshRenderer)
    meshRenderer: cc.MeshRenderer = null;
    mesh: cc.Mesh = null;
    __verts: cc.Vec2[] = [];
    __uvs: cc.Vec2[] = [];
    __colors: cc.Color[] = [];
    __indices: number[] = [];

    initSuccess: boolean = false;
    @property
    _spriteFrame: cc.SpriteFrame = null;
    @property({
        type: cc.SpriteFrame
    })
    get spriteFrame() {
        return this._spriteFrame;
    }
    set spriteFrame(v) {
        this._spriteFrame = v;
        this.setSpriteFrame();
        if (CC_EDITOR && v) {
            this.node.setContentSize(v.getOriginalSize())
        }
        this.updateMeshData();
    }

    onLoad() {
        _G.ddd = this;
        this.updateMeshData();
    }
    onDestroy() {
        this.node.removeComponent(this.meshRenderer)
    }

    /**初始化meshRenderer组件 清理掉多余的渲染组件*/
    initRenderComponent() {
        if (!this.node.getComponent(cc.MeshRenderer)) {
            this.node.addComponent(cc.MeshRenderer);
        }
        if (!this.meshRenderer) {
            this.meshRenderer = this.node.getComponent(cc.MeshRenderer);
            this.meshRenderer.enableAutoBatch = true;
            this.meshRenderer.mesh = null;

            let mat = cc.Material.getInstantiatedBuiltinMaterial("unlit")
            this.meshRenderer.setMaterial(0, mat);
            // this.mesh = new cc.Mesh();
            // this.mesh.init(vertexFmt2D, this.vertexesCount, true);
            this.setSpriteFrame()
        }
    }
    /**只更新顶点位置可以重写这个方法 */
    calculateMesh() {
        // this.updateColor();
        this.updateVerts();
        this.updateUVs();
        this.updateIndices();
    }

    // 更新数据
    updateMeshData() {
        this.initRenderComponent();
        if (this.meshRenderer) {
            this.calculateMesh();
            // console.log(this.__verts)
            // console.log(this.__uvs)
            // console.log(this.__colors)
            // console.log(this.__indices)
            this.mesh = new cc.Mesh();
            this.mesh.init(vertexFmt2D, this.vertexesCount, true);
            this.mesh.setVertices(gfx.ATTR_POSITION, this.__verts);
            this.mesh.setVertices(gfx.ATTR_UV0, this.__uvs);
            // debugger
            this.mesh.setIndices(this.__indices)
            this.meshRenderer.mesh = this.mesh;
        } else {
            console.error(new Error);
        }
    }

    setSpriteFrame() {
        let spriteFrame = this.spriteFrame;
        if (this.meshRenderer && spriteFrame) {
            let material = this.meshRenderer.getMaterial(0);
            if (material) {
                // Reset material
                // console.log('setSpriteFrame', spriteFrame)
                let texture = spriteFrame.getTexture();
                material.define("USE_DIFFUSE_TEXTURE", true);
                material.setProperty('diffuseTexture', texture);

            }
        }

    }

    updateColor() {
        let colors = this.__colors;
        let verts = this.__verts;
        for (let i = 0; i < verts.length; i++) {
            colors[i] = cc.color(255, 0, 0);
        }
    }
    updateVerts() {
        let cw = this.node.width, ch = this.node.height;
        let verts = this.__verts;
        let idx = 0;
        verts[idx++] = cc.v2(cw / 2, ch / 2);
        verts[idx++] = cc.v2(-cw / 2, ch / 2);
        verts[idx++] = cc.v2(-cw / 2, -ch / 2);
        verts[idx++] = cc.v2(cw / 2, -ch / 2);
        // console.log('updateVerts', verts);
    }
    updateUVs() {
        // console.log('updateUVs');
        if (!this.spriteFrame) {
            return;
        }
        let cw = this.node.width, ch = this.node.height;
        let spfUVs = this.spriteFrame['uv']
        let l = spfUVs[0];
        let t = spfUVs[1];
        let r = spfUVs[6];
        let b = spfUVs[7];
        // if (this.spriteFrame.isRotated()) {
        //     l = spfUVs[5];
        //     t = spfUVs[4];
        //     r = spfUVs[3];
        //     b = spfUVs[2];
        // }
        // console.log('spfUVs', spfUVs)
        // render data = verts = x|y|u|v|color|x|y|u|v|color|...
        // 填充render data中5个顶点的uv部分
        let verts = this.__verts;
        let uvs = this.__uvs;
        for (let i = 0; i < verts.length; i++) {
            let p = verts[i];
            let realPos = p.add(cc.v2(cw / 2, ch / 2));
            let percentX = realPos.x / cw;
            let percentY = 1 - realPos.y / ch;
            let u = percentX * (r - l) + l;
            let v = percentY * (t - b) + b;
            uvs[i] = cc.v2(u, v);
        }
        console.log('updateUVs', uvs);
    }
    // 判断一个点是否在三角形内
    _testInTriangle(point, triA, triB, triC) {
        let AB = triB.sub(triA), AC = triC.sub(triA), BC = triC.sub(triB), AD = point.sub(triA), BD = point.sub(triB);
        return (AB.cross(AC) >= 0 !== AB.cross(AD) < 0)  // D,C 在AB同同方向
            && (AB.cross(AC) >= 0 !== AC.cross(AD) >= 0) // D,B 在AC同同方向
            && (BC.cross(AB) > 0 !== BC.cross(BD) >= 0); // D,A 在BC同同方向
    }
    updateIndices() {
        // 计算顶点索引 
        let ids = [];
        const vertexes = [].concat(this.__verts);
        // console.log('vertexes', __vertexes)
        // 多边形切割，未实现相交的复杂多边形，确保顶点按顺序且围成的线不相交
        let index = 0, rootIndex = -1;
        let totalCross = 0;
        for (let i = 0; i < vertexes.length - 2; i++) {
            let p1 = vertexes[i];
            let p2 = vertexes[i + 1];
            let p3 = vertexes[i + 2];
            let v1 = p2.sub(p1);
            let v2 = p3.sub(p2);
            totalCross += v1.cross(v2);
        }
        // console.log('totalCross', totalCross)
        // 这里通过耳切法来确定索引
        while (vertexes.length >= 3) {
            const p1 = vertexes[index];
            const p2 = vertexes[(index + 1) % vertexes.length];
            const p3 = vertexes[(index + 2) % vertexes.length];

            const v1 = p2.sub(p1);
            const v2 = p3.sub(p2);
            let v = v1.cross(v2);
            let isTu = (v): boolean => {
                let isVTu = false;
                if (totalCross <= 0) {
                    if (v < 0) {
                        isVTu = true
                    }
                } else {
                    if (v >= 0) {
                        isVTu = true
                    }
                }
                // console.log('isVTu', isVTu)
                return isVTu
            }
            // console.log('v', v)
            if (isTu(v)) {
                // 是凸点
                let isIn = false;
                for (const p_t of vertexes) {
                    if (p_t !== p1 && p_t !== p2 && p_t !== p3 && this._testInTriangle(p_t, p1, p2, p3)) {
                        // 其他点在三角形内
                        isIn = true;
                        break;
                    }
                }
                if (!isIn) {
                    // 切耳朵，是凸点，且没有其他点在三角形内
                    ids = ids.concat([this.__verts.indexOf(p1), this.__verts.indexOf(p2), this.__verts.indexOf(p3)]);
                    // ids.push(this.vertexes.indexOf(p1), this.vertexes.indexOf(p2), this.vertexes.indexOf(p3__));
                    vertexes.splice(vertexes.indexOf(p2), 1);
                    rootIndex = index;
                    // console.log('找到',);
                } else {
                    index = (index + 1) % vertexes.length;
                    if (index === rootIndex) {
                        // console.log('循环一圈未发现1');
                        break;
                    }
                }
            } else {
                index = (index + 1) % vertexes.length;
                if (index === rootIndex) {
                    // console.log('循环一圈未发现2');
                    break;
                }
            }
            if (index > (vertexes.length - 1)) index = (vertexes.length - 1);
        }
        this.__indices = ids;

        console.log('updateIndices', ids);
    }



}
